﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using SharedLib.XmlDataModel;
using SharedLib.Helpers;

namespace SharedLib.DataAccess
{
    abstract public class XmlDataProvider<T> : IDataProvider<T> where T : XmlDataModelWithAttributesAndID, new()
    {
        private object _lockhelper = new object();
        protected XmlDocument doc;
        protected XmlElement root;

        public virtual string DataFolder
        {
            get { return "Data"; }
        }

        

        public virtual string FilePath
        {
            get { return DataFolder + "\\" + FileName; }
        }

        public virtual string GetMaxID()
        {
            return root.GetAttribute("max-id");
        }

        #region To be implemented
        public abstract string FileName { get; }
        public abstract string RootNodeName { get; }
        public abstract string DataItemPath { get; }
        #endregion
        

        public virtual void LoadItems()
        {
            if (!Directory.Exists(DataFolder))
            {
                Directory.CreateDirectory(DataFolder);
            }

            doc = new XmlDocument();
            if (!File.Exists(FilePath))
            {
                root = doc.AppendChild(doc.CreateElement(RootNodeName)) as XmlElement;
                root.SetAttribute("max-id", "0");
                doc.Save(FilePath);
            }
            else
            {
                doc.Load(FilePath);
                root = doc.SelectSingleNode(RootNodeName) as XmlElement;
                if (root == null) throw new Exception("Root Node \"" + RootNodeName  + "\" not found!");
            }
        }

        
        public virtual void SaveItems()
        {
            //lock (_lockhelper)
            //{
                doc.Save(FilePath);
            //}
        }

        public virtual List<T> GetItems()
        {
            List<T> rtn = new List<T>();
            foreach (XmlNode node in doc.SelectNodes(DataItemPath))
            {
                T item = new T();
                item.LoadXmlNode(node);
                rtn.Add(item);
            }
            return rtn;
        }

        private XmlElement GetNodeByID(string id)
        {
            return doc.SelectSingleNode(String.Format(DataItemPath + "[@id='{0}']", id)) as XmlElement;
        }

        public virtual T GetItemByID(string id)
        {
            XmlNode node = GetNodeByID(id);
            if (node == null) return default(T);
            T rtn = new T();
            rtn.LoadXmlNode(node);
            return rtn;
        }

        public virtual void AddItem(T rawItem)
        {
            lock (_lockhelper)
            {
                int maxID = Convert.ToInt32(GetMaxID()) + 1;
                rawItem.ID = maxID.ToString();
                XmlElement node = rawItem.ToXmlNode(doc);
                ProcessItemToAdd(node, rawItem);
                root.AppendChild(node);
                root.SetAttribute("max-id", rawItem.ID);
                SaveItems();
            }
        }

        protected virtual void ProcessItemToAdd(XmlElement node, T rawItem)
        {
            
        }

        public virtual void UpdateItem(T item)
        {
            lock (_lockhelper)
            {
                XmlNode oldNode = GetNodeByID(item.ID);
                if (oldNode != null)
                {
                    XmlHelper.UpdateXmlNode(item.ToXmlNode(doc), oldNode);
                    SaveItems();
                }
            }
        }

        public virtual void RemoveItem(string id)
        {
            lock (_lockhelper)
            {
                XmlNode oldNode = GetNodeByID(id);
                if (oldNode != null)
                {
                    root.RemoveChild(oldNode);
                    SaveItems();
                }
            }
        }
    }
}
